Writing a COM component
This section gives three examples of how to write a third party COM component in Visual Basic to be used in the Architect environment. The first example implements a simple mathematical function (Example 1), the second one adds a configuration GUI to the first component (Example 2), and the third example adds component persistence so that the Blueprint can keep parameters (Example 3). These components can then be integrated within the Architect environment using the COM Wrapper block.
Example 1: Implementing a simple component
Task description
Implement the following mathematical function: y = a1*x1 + a2*x2, where x1 and x2 are the input variables, y is the output variable, and a1 and a2 are the coefficient (properties or parameters) of the function.
Implementation steps (see example MyComponent1)
-
Load project COMWrapperTemplate.vbp
-
Project is an ActiveX DLL VB project
-
Save as your own project file; rename project
-
COM Program ID is ProjectName.ClassName
-
-
Select ICSenseUserBlock in Object drop-down box
-
Select block functions in Procedure drop-down box
-
Implement functions as follows:
-
GetInputVariableList: return x1, x2
-
GetOutputVariableList: return y
-
GetPropertyList: return a1, a2
-
Initialise: a1, a2 with values as persisted in blueprint
-
Execute:
-
if all input qualities good then y = a1*x1 + a2*x2,
else y is bad
-
-
ShowEditor: empty
-
-
Implementation Details
-
All function parameters are Arrays of Variants
-
Heterogeneous types in arrays allowed
-
COM Wrapper data type IDs:
-
-
DT_DOUBLE = 1
-
DT_INTEGER = 2
-
DT_STRING = 3
-
-
COM Wrapper quality values:
-
-
Q_GOOD = 1
-
Q_BAD = 0
-
-
-
Compile to DLL: File/Make Component1.dll (component gets automatically registered in Windows registry after compilation of DLL by VB)
-
Create blueprint with COM Wrapper Block (see diagram below)
-
Connect COM Wrapper Block to component:
-
Program ID = ProjectName.ClassName
-
-
Map input fields to component input variables
-
Set property values (persisted in blueprint)
-
Simulate blueprint
Visual Basic code of COM component (MyComponent1)
Implements CSENSEUSERBLOCKLib.ICSenseUserBlock
Option Explicit
'This example file implements a function y = a1*x1 + a2*x2
'The COM Wrapper block manages the property values (a1, a2)
'Constants defining Architect data type IDs
Const DT_DOUBLE As Integer = 1
Const DT_INTEGER As Integer = 2
Const DT_STRING As Integer = 3
'Constants defining Architect quality values
Const Q_GOOD As Integer = 1
Const Q_BAD As Integer = 0
'Constants number of variables and properties
Const NUM_INPUTS As Integer = 2
Const NUM_OUTPUTS As Integer = 1
Const NUM_PROPERTIES As Integer = 2
'Arrays containing the output variable values and qualities
Dim MyOutV(0 To NUM_OUTPUTS - 1) As Variant
Dim MyOutQ(0 To NUM_OUTPUTS - 1) As Integer
'Variables containing property values
Dim a1, a2 As Double
Private Sub ICSenseUserBlock_GetInputVariableList(Names As Variant, Types As Variant)
'Arrays containing input variable descriptors
Dim theNames(0 To NUM_INPUTS - 1) As String
Dim theTypes(0 To NUM_INPUTS - 1) As Integer
theNames(0) = "x1"
theTypes(0) = DT_DOUBLE
theNames(1) = "x2"
theTypes(1) = DT_DOUBLE
'Return the input variable descriptors
Names = theNames
Types = theTypes
End Sub
Private Sub ICSenseUserBlock_GetOutputVariableList(Names As Variant, Types As Variant)
'Arrays containing output variable descriptors
Dim theNames(0 To NUM_OUTPUTS - 1) As String
Dim theTypes(0 To NUM_OUTPUTS - 1) As Integer
theNames(0) = "y"
theTypes(0) = DT_DOUBLE
'Return the output variable descriptors
Names = theNames
Types = theTypes
End Sub
Private Sub ICSenseUserBlock_GetPropertyList(Names As Variant, Types As Variant)
'Arrays containing property descriptors
Dim theNames(0 To NUM_PROPERTIES - 1) As String
Dim theTypes(0 To NUM_PROPERTIES - 1) As Integer
theNames(0) = "a1"
theTypes(0) = DT_DOUBLE
theNames(1) = "a2"
theTypes(1) = DT_DOUBLE
'Return the property descriptors
Names = theNames
Types = theTypes
End Sub
Private Sub ICSenseUserBlock_Initialise(ByVal PropertyValues As Variant)
'Initialise all properties passed in by COM Wrapper block
a1 = PropertyValues(0)
a2 = PropertyValues(1)
'Initialise output variables
MyOutV(0) = 0#
MyOutQ(0) = Q_BAD
End Sub
Private Sub ICSenseUserBlock_Execute(ByVal InputValues As Variant, ByVal InputQualities As Variant, ByVal Timestamp As Variant, OutputValues As Variant, OutputQualities As Variant)
'Calculate output values and qualities
'Timestamps is in GMT
If InputQualities(0) = Q_BAD Or InputQualities(1) = Q_BAD Then
MyOutV(0) = 0#
MyOutQ(0) = Q_BAD
Else
MyOutV(0) = a1 * InputValues(0) + a2 * InputValues(1)
MyOutQ(0) = Q_GOOD
End If
'Return the output variables
OutputValues = MyOutV
OutputQualities = MyOutQ
End Sub
Private Sub ICSenseUserBlock_ShowEditor()
End Sub
Example 2: Implement a Configuration GUI
Task description
Add a configuration GUI to the COM component in the first example for editing parameters, a1 and a2.
Implementation steps (see example MyComponent2)
-
Make GetPropertyList, Initialise functions empty
-
Initialise params in Class_Initialise
-
Add Form of type Dialog
-
Add labels, text boxes for parameters to form
-
Add OK, Cancel button actions
-
Implement ShowEditor to show form modally
-
Compile to DLL: File/Make Component2.dll (component gets automatically registered in Windows registry after compilation of DLL by VB)
-
Create Blueprint with COM Wrapper Block
-
Connect COM Wrapper Block to component
-
Map input fields to component variables
-
Set property values using new editor
-
Simulate blueprint
Visual Basic code of COM component (MyComponent2)
Implements CSENSEUSERBLOCKLib.ICSenseUserBlock
Option Explicit
'This example file implements a function y = a1*x1 + a2*x2
'This component manages the editing of the property values (a1, a2)
'It does not persist them in the blueprint
'Constants defining Architect data type IDs
Const DT_DOUBLE As Integer = 1
Const DT_INTEGER As Integer = 2
Const DT_STRING As Integer = 3
'Constants defining Architect quality values
Const Q_GOOD As Integer = 1
Const Q_BAD As Integer = 0
'Constants number of variables and properties
Const NUM_INPUTS As Integer = 2
Const NUM_OUTPUTS As Integer = 1
Const NUM_PROPERTIES As Integer = 2
'Arrays containing the output variable values and qualities
Dim MyOutV(0 To NUM_OUTPUTS - 1) As Variant
Dim MyOutQ(0 To NUM_OUTPUTS - 1) As Integer
'Variables containing property values
Dim a1, a2 As Double
Private Sub Class_Initialise()
a1 = 0#
a2 = 0#
End Sub
Private Sub ICSenseUserBlock_GetInputVariableList(Names As Variant, Types As Variant)
'Arrays containing input variable descriptors
Dim theNames(0 To NUM_INPUTS - 1) As String
Dim theTypes(0 To NUM_INPUTS - 1) As Integer
theNames(0) = "x1"
theTypes(0) = DT_DOUBLE
theNames(1) = "x2"
theTypes(1) = DT_DOUBLE
'Return the input variable descriptors
Names = theNames
Types = theTypes
End Sub
Private Sub ICSenseUserBlock_GetOutputVariableList(Names As Variant, Types As Variant)
'Arrays containing output variable descriptors
Dim theNames(0 To NUM_OUTPUTS - 1) As String
Dim theTypes(0 To NUM_OUTPUTS - 1) As Integer
theNames(0) = "y"
theTypes(0) = DT_DOUBLE
'Return the output variable descriptors
Names = theNames
Types = theTypes
End Sub
Private Sub ICSenseUserBlock_GetPropertyList(Names As Variant, Types As Variant)
End Sub
Private Sub ICSenseUserBlock_Initialise(ByVal PropertyValues As Variant)
MyOutV(0) = 0#
MyOutQ(0) = Q_BAD
End Sub
Private Sub ICSenseUserBlock_Execute(ByVal InputValues As Variant, ByVal InputQualities As Variant, ByVal Timestamp As Variant, OutputValues As Variant, OutputQualities As Variant)
'Calculate output values and qualities
'Timestamps is in GMT
If InputQualities(0) = Q_BAD Or InputQualities(1) = Q_BAD Then
MyOutV(0) = 0#
MyOutQ(0) = Q_BAD
Else
MyOutV(0) = a1 * InputValues(0) + a2 * InputValues(1)
MyOutQ(0) = Q_GOOD
End If
'Return the output variables
OutputValues = MyOutV
OutputQualities = MyOutQ
End Sub
Private Sub ICSenseUserBlock_ShowEditor()
Dim theForm As ConfigDialogForm
Set theForm = New ConfigDialogForm
theForm.a1 = a1
theForm.a2 = a2
theForm.Show vbModal
a1 = theForm.a1
a2 = theForm.a2
End Sub
Example 3: Implement a Component Persistence
Task description
Add persistence of parameters a1 and a2 to the COM component in Example 2 by using standard COM persistence. The loading and saving of Blueprints then keeps parameters.
Implementation steps (see example MyComponent3)
-
Set Class1 Persistable property to Persistable
-
Implement persistence functions:
-
Class_InitProperties: called for new component
-
Class_ReadProperties: called when loading
-
Class_WriteProperties: called when saving
-
-
Compile to DLL: File/Make Component3.dll (component gets automatically registered in Windows registry after compilation of DLL by VB)
-
Create Blueprint with COM Wrapper Block
-
Connect COM Wrapper Block to component
-
Map input fields to component variables
-
Set property values using new editor
-
Simulate blueprint
Visual Basic code of COM component (MyComponent3)
Implements CSENSEUSERBLOCKLib.ICSenseUserBlock
Option Explicit
'This example file implements a function y = a1*x1 + a2*x2
'This component manages the editing of the property values (a1, a2)
'It also persists them in the blueprint using property bags
'Constants defining Architect data type IDs
Const DT_DOUBLE As Integer = 1
Const DT_INTEGER As Integer = 2
Const DT_STRING As Integer = 3
'Constants defining Architect quality values
Const Q_GOOD As Integer = 1
Const Q_BAD As Integer = 0
'Constants number of variables and properties
Const NUM_INPUTS As Integer = 2
Const NUM_OUTPUTS As Integer = 1
Const NUM_PROPERTIES As Integer = 2
'Arrays containing the output variable values and qualities
Dim MyOutV(0 To NUM_OUTPUTS - 1) As Variant
Dim MyOutQ(0 To NUM_OUTPUTS - 1) As Integer
'Variables containing property values
Dim a1, a2 As Double
Private Sub Class_InitProperties()
a1 = 0#
a2 = 0#
End Sub
Private Sub Class_ReadProperties(PropBag As PropertyBag)
a1 = PropBag.ReadProperty("a1")
a2 = PropBag.ReadProperty("a2")
End Sub
Private Sub Class_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("a1", a1)
Call PropBag.WriteProperty("a2", a2)
End Sub
Private Sub ICSenseUserBlock_GetInputVariableList(Names As Variant, Types As Variant)
'Arrays containing input variable descriptors
Dim theNames(0 To NUM_INPUTS - 1) As String
Dim theTypes(0 To NUM_INPUTS - 1) As Integer
theNames(0) = "x1"
theTypes(0) = DT_DOUBLE
theNames(1) = "x2"
theTypes(1) = DT_DOUBLE
'Return the input variable descriptors
Names = theNames
Types = theTypes
End Sub
Private Sub ICSenseUserBlock_GetOutputVariableList(Names As Variant, Types As Variant)
'Arrays containing output variable descriptors
Dim theNames(0 To NUM_OUTPUTS - 1) As String
Dim theTypes(0 To NUM_OUTPUTS - 1) As Integer
theNames(0) = "y"
theTypes(0) = DT_DOUBLE
'Return the output variable descriptors
Names = theNames
Types = theTypes
End Sub
Private Sub ICSenseUserBlock_GetPropertyList(Names As Variant, Types As Variant)
End Sub
Private Sub ICSenseUserBlock_Initialise(ByVal PropertyValues As Variant)
MyOutV(0) = 0#
MyOutQ(0) = Q_BAD
End Sub
Private Sub ICSenseUserBlock_Execute(ByVal InputValues As Variant, ByVal InputQualities As Variant, ByVal Timestamp As Variant, OutputValues As Variant, OutputQualities As Variant)
'Calculate output values and qualities
'Timestamps is in GMT
If InputQualities(0) = Q_BAD Or InputQualities(1) = Q_BAD Then
MyOutV(0) = 0#
MyOutQ(0) = Q_BAD
Else
MyOutV(0) = a1 * InputValues(0) + a2 * InputValues(1)
MyOutQ(0) = Q_GOOD
End If
'Return the output variables
OutputValues = MyOutV
OutputQualities = MyOutQ
End Sub
Private Sub ICSenseUserBlock_ShowEditor()
Dim theForm As ConfigDialogForm
Set theForm = New ConfigDialogForm
theForm.a1 = a1
theForm.a2 = a2
theForm.Show vbModal
a1 = theForm.a1
a2 = theForm.a2
End Sub
Related topics: